package com.yeskery.nut.extend.responsive;

import com.yeskery.nut.core.MediaType;
import com.yeskery.nut.core.NutException;
import com.yeskery.nut.core.Request;
import com.yeskery.nut.core.Response;

/**
 * 默认的响应式处理对象
 * @author sprout
 * 2022-06-08 17:21
 */
public class DefaultResponsive implements Responsive {

    /** 响应转换接口 */
    private final ResponsiveConvert responsiveConvert;

    /** 响应媒体类型 */
    private final MediaType mediaType;

    /** 请求响应对象 */
    private final ThreadLocal<RequestAndResponse> threadLocal = new InheritableThreadLocal<>();

    /**
     * 构建默认的响应式处理对象
     * @param responsiveConvert 响应转换接口
     * @param mediaType 响应媒体类型
     */
    public DefaultResponsive(ResponsiveConvert responsiveConvert, MediaType mediaType) {
        this.responsiveConvert = responsiveConvert;
        this.mediaType = mediaType;
    }

    @Override
    public <T> T getBody(Class<T> clazz) {
        RequestAndResponse requestAndResponse = threadLocal.get();
        if (requestAndResponse == null || requestAndResponse.request == null) {
            throw new NutException("Invalid Request.");
        }
        return responsiveConvert.convertFromString(requestAndResponse.request.getBodyAsString(), clazz);
    }

    @Override
    public <T> void writeBody(T data) {
        RequestAndResponse requestAndResponse = threadLocal.get();
        if (requestAndResponse == null || requestAndResponse.response == null) {
            throw new NutException("Invalid Request.");
        }
        if (requestAndResponse.response.isResponse()) {
            throw new NutException("Response Already Output.");
        }
        if (data instanceof String) {
            requestAndResponse.response.write((String) data, mediaType);
        } else {
            String responseBody = responsiveConvert.convertTo(data);
            requestAndResponse.response.write(responseBody, mediaType);
        }
    }

    /**
     * 获取响应转换接口
     * @return 响应转换接口
     */
    public ResponsiveConvert getResponsiveConvert() {
        return responsiveConvert;
    }

    /***
     * 设置请求响应对象
     * @param requestAndResponse 请求响应对象
     */
    void set(RequestAndResponse requestAndResponse) {
        threadLocal.set(requestAndResponse);
    }

    /**
     * 移除请求响应对象
     */
    void remove() {
        threadLocal.remove();
    }

    /**
     * 请求响应对象
     * @author sprout
     * 2022-06-08 18:23
     */
    static class RequestAndResponse {
        /** 请求对象 */
        private final Request request;

        /** 响应对象 */
        private final Response response;

        RequestAndResponse(Request request, Response response) {
            this.request = request;
            this.response = response;
        }
    }
}
